package Day023_设计模式_动态代理.demo4_动态代理;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author：pengzhilin
 * @Date: 2020/5/17 10:26
 */
public class XiMen {
    public static void main(String[] args) {
        /*
            案例: 金莲要找西门happy
            代理模式的定义：被代理者没有能力或者不愿意去完成某件事情，那么就需要找个人代替自己去完成这件事,这个人就是代理者,
            所以代理模式包含了3个角色: 被代理角色     代理角色    抽象角色(协议)

         */
        // 不请代理: 金莲直接找西门happy
        // 创建金莲对象
        JinLian jl = new JinLian();

        // happy
        // jl.happy();

        // 请代理: 静态代理,代理类真实存在
        Happy wp = new WangPo(jl);// wp:代理对象   WangPo类: 代理类   Happy接口: 协议  JinLian: 被代理类
        wp.happy();

        /*
            问题:
                1.金莲不方便直接找西门happy
                2.金莲的happy方法需要增强一下,例如:happy之前需要开房,happy之后需要打扫战场

            静态代理: 代理类是真实存在的,通过代理类产生代理对象
            动态代理: 代理类是不真实存在的,在程序运行中,直接产生代理对象
            前提: 被代理类需要实现接口
            动态代理实现获取代理对象:
                jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象
                Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
                    参数1loader:被代理类的类加载器
                    参数2interfaces: 被代理类所有实现的接口的Class对象
                    参数3InvocationHandler: 执行处理类
                    前2个参数是为了帮助在jvm内部生成被代理类的代理对象,第3个参数用来监听代理对象调用的方法,帮助我们代理对象调用方法
         */
        System.out.println("=========================================");

        // 使用动态代理直接产生金莲的代理对象
        // 动态代理: 代理类是不真实存在的,但代理类是一定实现了被代理类的接口的
        // p:动态代理产生的代理对象 代理类是不真实存在的
        Happy p = (Happy) Proxy.newProxyInstance(JinLian.class.getClassLoader(), JinLian.class.getInterfaces(), new InvocationHandler() {

            public void openHouse(){
                System.out.println("王婆以做衣服的名义开好房间,把2人约到房间...");
            }

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 回调方法: 当代理对象调用了方法,就会来执行该invoke方法, 在该方法中就可以增强被代理类的方法
                // 参数1: 生成的代理对象 这里就是p这个代理对象 (慎用)
                // 参数2: 当前代理对象执行的方法 这里method就是happy()方法对象
                // 参数3: 当前代理对象执行的方法,传入的实际参数
                // 返回值:当前代理对象执行的方法的返回值
                // System.out.println("invoke");
                // 王婆开房
                openHouse();

                // 方式一:
                // 如果代理对象调用的方法没有参数,那么args等于null
                /*if (args == null) {
                    // 金莲happy
                    method.invoke(jl);
                } else if (args.length == 1) {

                    // 金莲sleep
                    method.invoke(jl,args[0]);
                }*/

                // 方式二:
                // method.invoke(jl,args);

                // 方式三:
                JinLian jl = JinLian.class.newInstance();
                method.invoke(jl,args);

                // 王婆打扫
                System.out.println("王婆打印战场...");

                return null;
            }
        });

        // 代理happy
        p.happy();// 无参数

        System.out.println("=========================");

        p.sleep(10);// 有参数

/*
        //
        method(null);
        String[] arr2 = {"jack"};
        method(arr2);


        // ------------ ---------------------------
        method("jack","rose","lily","lucy");
        String[] arr = {"jack","rose","lily","lucy"};
        method(arr);*/
    }

    // 可变参数
    public static void method(Object... args){
            // "jack","rose","lily","lucy"
    }


}
